<script lang="ts" setup>
import { ref, type VNode } from "vue";
import { useAppStore } from "~/store/appStore";
import type { NavItem } from "~/types";
import { BASE_URL } from "~/api/base";
import { useBlogById } from "~/api/blog";
import type { Blog } from "@/types";
import { Snackbar } from "@varlet/ui";
const AppStore = useAppStore();
const props = defineProps({
  data: {
    type: Object as PropType<Blog>,
    required: true,
  },
  close: {
    type: Function as PropType<() => void>,
    required: true,
  },
});
if (!props.data.id) {
  Snackbar.error("文章不存在");
  props.close();
}
if (process.client) {
  AppStore.closeDetails = () => {
    AppStore.closeDetails = undefined;
    AppStore.editArtical = undefined;
    AppStore.showDetails = false;
    props.close();
  };
  AppStore.editArtical = () => {
    AppStore.editArtical = undefined;
    AppStore.showDetails = false;
    AppStore.artical = data.value?.data;
    useRouter().push({ name: "edit" });
  };
}
const showBodyDom = ref<HTMLElement | null>(null);
const MdViewerDom = ref<any>(null);
const svgId = Math.floor(Math.random() * 520);
const { data } = await useBlogById(props.data.id ?? "");
const artical = computed(() => {
  return {
    ...props.data,
    ...data.value?.data,
  };
});
const { articalNavList, articalSelectNavId } = toRefs(AppStore);
useHead({
  title: artical.value?.title,
  meta: [
    {
      name: "description",
      content: artical.value?.desc,
    },
    {
      name: "keywords",
      content: "雪貂神社,雪貂,博客," + artical.value?.tags,
    },
  ],
});
const idMap = new Map<string, string>();
function parseNav(e: VNode) {
  if (!e.el || !showBodyDom.value) return;
  const dom = e.el.querySelector("#md-editor-v3-preview") as HTMLElement;
  const list = dom.querySelectorAll("h1,h2,h3,h4,h5,h6");
  const navList = new Array<NavItem>();
  list.forEach((item) => {
    if (!(item instanceof HTMLElement)) {
      return;
    }
    idMap.set(item.id, item.getAttribute("data-line") ?? "");
    navList.push({
      level: parseInt(item.tagName.slice(1)),
      name: item.innerText,
      id: item.id,
      top: item.offsetTop,
    });
  });
  articalNavList.value = navList;
  articalSelectNavId.value = navList[0]?.id;
  showBodyDom.value.addEventListener("scroll", watchScroll(), {
    passive: true,
  });
}
let _selectNavId: string | undefined;
let isSrcoll = false;
function watchScroll(delay = 300) {
  let timmer: any;
  if (!MdViewerDom.value) {
    throw new Error("MdViewerDom is undefined");
  }
  const dom = MdViewerDom.value.$el.querySelector(
    "#md-editor-v3-preview"
  ) as HTMLElement;

  const childNodes = [...dom.childNodes].filter(
    (item: ChildNode) =>
      item instanceof HTMLElement && item.nodeName.includes("H")
  );
  return (e: Event) => {
    if (isSrcoll) return;
    if (timmer) {
      clearTimeout(timmer);
    }
    if (e.type !== "scroll") {
      return;
    }
    timmer = setTimeout(() => {
      timmer = undefined;
      if (!(e.target instanceof HTMLElement)) return;
      const scrollTop = e.target.scrollTop - 30;
      childNodes.some((item: ChildNode) => {
        if (!(item instanceof HTMLElement)) {
          return;
        }
        if (item.offsetTop >= scrollTop) {
          articalSelectNavId.value = item.id;
          _selectNavId = item.id;
          return true;
        }
      });
    }, delay);
  };
}
watch(articalSelectNavId, () => {
  if (!showBodyDom.value || _selectNavId === articalSelectNavId.value) return;
  const lineId = idMap.get(articalSelectNavId.value ?? "");
  const dom = showBodyDom.value.querySelector(
    `[data-line='${lineId}']`
  ) as HTMLElement;
  if (!dom) return;
  isSrcoll = true;
  showBodyDom.value?.scrollTo({
    top: dom.offsetTop,
    behavior: "smooth",
  });
  setTimeout(() => {
    isSrcoll = false;
  }, 300);
});
onMounted(() => {
  useRouter().push({ name: "blog", query: { id: props.data.id, svgId } });
  // 监听系统返回
  window.addEventListener("popstate", (e) => {
    e.preventDefault();
    AppStore.closeDetails && AppStore.closeDetails();
  });
});
onUnmounted(() => {
  articalNavList.value = [];
  articalSelectNavId.value = undefined;
  showBodyDom.value?.removeEventListener("scroll", watchScroll());
});
</script>

<template>
  <div
    class="showBody"
    ref="showBodyDom"
  >
    <img
      :src="`/svg/${svgId}.svg`"
      class="background"
    />
    <header>
      <div class="user">
        <img
          v-if="artical?.user?.avatar"
          class="avatar"
          :src="`${BASE_URL}/public/avatar/1219460281`"
          alt="avatar"
          share="avatar"
          crossorigin=""
        />
        <span
          v-else
          share="avatar"
        >
          <Icon icon="solar:user-circle-broken"></Icon>
        </span>
        <span share="username">
          {{ artical?.user?.name ? artical?.user?.name : "用户已注销" }}
        </span>
      </div>
      <h1>
        <span share="title">{{ artical?.title }}</span>
      </h1>
      <div
        v-if="artical?.tags"
        style="display: flex; flex-direction: row-reverse"
      >
        <template
          v-for="(item, index) in artical.tags.split(',')"
          :key="item"
        >
          <span
            :share="`tag${index}`"
            v-if="item.length > 0"
            class="tag"
          >
            {{ item }}
          </span>
        </template>
      </div>
      <div v-else></div>
    </header>
    <Preview
      ref="MdViewerDom"
      @vue:mounted="parseNav"
      :model-value="artical?.text"
      :show-code-row-number="true"
    ></Preview>
  </div>
</template>

<style lang="less" scoped>
.showBody {
  height: 100vh;
  padding: 0.5em;
  overflow-y: auto;
  scroll-behavior: smooth;
  background-color: var(--color-body);
  .background {
    position: fixed;
    top: 50%;
    right: 10%;
    height: 80vh;
    aspect-ratio: 1/1;
    transform: translateY(-50%);
    z-index: 1;
    opacity: 0.1;
    animation: breath 3s infinite alternate linear;
  }
  @keyframes breath {
    from {
      transform: scale(1) translateY(-50%);
    }
    to {
      transform: scale(0.95) translateY(-50%);
    }
  }
  & > *:not(.background, header) {
    z-index: 2;
    background: none;
  }
  header {
    margin: 0 0.5em;
    position: sticky;
    top: 0em;
    background-color: inherit;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.5em 1em;
    border-radius: 0.5em;
    z-index: 13;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.27);
    & > * {
      flex: 1;
      overflow: auto;
    }
    h1 {
      text-overflow: ellipsis;
      text-align: center;
      white-space: nowrap;
      overflow: hidden;
      flex: 1;
    }
    .user {
      display: flex;
      align-items: center;
      .avatar {
        border-radius: 1em;
        width: 1.5em;
        aspect-ratio: 1/1;
        margin-right: 0.5em;
      }
      span {
        display: grid;
        place-items: center;
        svg {
          font-size: 1.5em;
          margin-right: 0.3em;
          clip-path: circle(50% at 50% 50%);
          background-color: var(--bg-200);
        }
      }
    }
    .tag {
      background-color: var(--color-primary);
      color: var(--color-body);
      padding: 0.2em 0.5em;
      border-radius: 0.5em;
      margin: 0 0.2em;
      font-size: 0.8em;
      font-weight: 500;
      letter-spacing: 0.5px;
    }
  }
}
</style>
